/* * * * M A P V I S I O N   L I C E N S E  *****************************************************************
 *
 * This MapVision software is © Filip Zavadil 2013. It is licensed under the LGPL license.
 * This MapVision software dynamically links to unmodified Qt5 Library.
 *
 * The Qt5 Library is © 2013 Qt® and/or its subsidiary(-ies), and is licensed under the
 * GNU Lesser General Public License version 2.1 with Qt® LGPL exception version 1.1.
 * Qt5 library is free software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License, version 2.1, as published by the Free Software Foundation.
 * Qt5 library is provided “AS IS”, without WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 *
 * As an additional permission to the GNU Lesser General Public License version 2.1, the object
 * code form of a “work that uses the Library” may incorporate material from a header file that is
 * part of the Library. You may distribute such object code under terms of your choice,
 * provided that: (i) the header files of the Library have not been modified; and (ii)
 * the incorporated material is limited to numerical parameters, data structure layouts, accessors,
 * macros, inline functions and templates; and (iii) you comply with the terms of Section 6 of the
 * GNU Lesser General Public License version 2.1.
 *
 * Moreover, you may apply this exception to a modified version of the Library, provided that such
 * modification does not involve copying material from the Library into the modified Library’s header
 * files unless such material is limited to (i) numerical parameters; (ii) data structure layouts;
 * (iii) accessors; and (iv) small macros, templates and inline functions of five lines or less in length.
 *
 * Furthermore, you are not required to apply this additional permission to a modified version of the Library.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this package;
 * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

 * The source code for Qt 5.X SDK is available from Qt Project here:
 * http://download.qt-project.org/official_releases/qtcreator/2.7/2.7.0/qt-creator-2.7.0-src.zip.
 *
 * ****************************** M A P V I S I O N    S O F T W A R E  ************************************
 *
 * Author:       Filip Zavadil
 * Description:  Software for displaying and exporting map tiles.
 * The sources and executables of MapVision software are available:
 *    - from project hosting on CodePlex.com :   http://mapvision.codeplex.com
 *    - from GIT repositories on Gitorious.org:  https://gitorious.org/mapvision
 * Visit MapVision fanpage on Facebook.com:      https://www.facebook.com/pages/Mapvision/631827753513935
 *
 * *********************************************************************************************************
*/

#include "export.h"
#include <QRect>
#include "dialogexportcutting.h"



Export::Export(QWidget *parent,QList<Layer*> * layers_)
{
    layers=layers_;
    map = parent->findChild<MapView *>("map");
    selection = map->findChild<SelectionRubberBand *>("selection");
    scene = map->getScene();
    dialog = new DialogExport(parent,map);
    dialogCutting = new DialogExportCutting(parent,map,layers);
    connect(this,SIGNAL(tilesRendered(QString)),dialogCutting,SLOT(tilesRendered(QString)));
    connect(this,SIGNAL(messageCutting(QString)),dialogCutting,SLOT(messageCutting(QString)));
    connect(this,SIGNAL(progress(int)),dialogCutting,SLOT(setProgress(int)));
}

void Export::exec()
{
    foreach (Layer * layer, *layers) {
        qDebug() << layer->getTile(QPoint(0,0),1).size();
    }
}

void Export::exportTiles(QList<int> zooms)
{
    QList<Layer *> layersOrdered;
    foreach (Layer * layer, *layers) {
        layersOrdered.insert(layer->getZvalue(),layer);
    }

    foreach (int zoom, zooms) {

        QRect tileRect = selection->getRectTiles(zoom,ZavaProj::BOTTOM);

        for (int x=tileRect.left(); x<=tileRect.right();x++)
        {
            for (int y=tileRect.bottom(); y<=tileRect.top();y++)
            {
                QList<QImage> images;

                QImage image(256,256,QImage::Format_ARGB32);
                QPainter * painter = new QPainter(&image);
                painter->setRenderHint(QPainter::Antialiasing);

                foreach (Layer * layer, layersOrdered) {
                    if (layer->getVisible()){
                        images << layer->getTile(QPoint(x,y),zoom);

                        qDebug()<<layer->getLayerName()<<layer->getTile(QPoint(x,y),zoom).size() << x<<y<<zoom;
                    }

                }
                painter->begin(&image);
                foreach (QImage imageTile,images)
                {
                    painter->drawImage(0,0,imageTile);
                }
                painter->end();

                qDebug()<< image.save(QString::number(zoom*100+x*10+y)+".png");
            }
        }
    }
}

void Export::makePicture()
{
    dialog->setTypeTitle(1,"Export Map As An Image");
    dialog->show();
}

void Export::cutting(QList<int> zooms,QString path)
{
    QSize preSize = map->maximumSize();
    map->setMaximumSize(512,512);
    int preZoom = map->getZoom();

    QPointF preCenter = map->getCenterLonLat();

    map->setViewScale(100);


    this->infoCutting(zooms);

    int countTemp=0;
    int countTemp2=0;

    emit messageCutting("TILES CUTTING NOW STARTED :)");

    foreach (int z, zooms) {
        map->setZoom(z);
        map->refresh();
        QTimer t;
        t.start(500);
        QEventLoop loop;
        QObject::connect(&t, SIGNAL(timeout()),&loop, SLOT(quit()));
        loop.exec();

        QPoint NW = zavaproj.pixels2tileFormat(selection->getRectPixels(z).topLeft(),z,ZavaProj::BOTTOM);
        QPoint SE = zavaproj.pixels2tileFormat(selection->getRectPixels(z).bottomRight(),z,ZavaProj::BOTTOM);

        map->setCenterLonLat(zavaproj.tileFormat2lonlat(QPoint(NW.x(),SE.y()),z,ZavaProj::BOTTOM));

        QTimer t2;
        t2.start(300);
        QEventLoop loop2;
        QObject::connect(&t2, SIGNAL(timeout()),&loop2, SLOT(quit()));
        loop2.exec();


        for (int x=NW.x(); x<=SE.x(); x++){
            for (int y=SE.y(); y<=NW.y();y++){

                if (!dialogCutting->isRunning){
                    map->setZoom(preZoom);
                    map->setCenterLonLat(preCenter);
                    map->setMaximumSize(preSize);
                    return;
                }


                if (countTemp2 > 100){
                    countTemp2 = 0;
                    map->refresh();
                    QTimer t4;
                    t4.start(300);
                    QEventLoop loop4;
                    QObject::connect(&t4, SIGNAL(timeout()),&loop4, SLOT(quit()));
                    loop4.exec();
                }


                map->setCenterLonLat(zavaproj.tileFormat2lonlat(QPoint(x,y),z,ZavaProj::BOTTOM));
                QTimer t2;
                t2.start(200);
                QEventLoop loop2;
                QObject::connect(&t2, SIGNAL(timeout()),&loop2, SLOT(quit()));
                loop2.exec();
                renderTiles(path,z,x,y);
                countTemp++;
                countTemp2++;
                emit tilesRendered(QString::number(countTemp)+"/"+QString::number(countCutting));
                emit progress(int((double(countTemp)/double(countCutting))*100));
            }
        }
        emit messageCutting("Tiles for "+ QString::number(z)+". zoom level are cutted. ");

    }

    map->setZoom(preZoom);
    map->setCenterLonLat(preCenter);
    map->setMaximumSize(preSize);

    emit messageCutting("All "+ QString::number(countCutting)+" tiles suxcessfully rendered. ");

}


void Export::renderTiles(QString path,int z,int x,int y)
{

    QImage img(QSize(256,256),QImage::Format_ARGB32);


    painter = new QPainter();
    painter->begin(&img);

    map->getScene()->render(painter,QRect(0,0,256,256),QRect(QPoint(x*256,zavaproj.convertYaxis(QPoint(x,y),z).y()*256),QSize(256,256)),Qt::KeepAspectRatio);


    saveMapTile(path,z,x,y,img);

    painter->end();

    // map->getScene()->addRect(QRect(QPoint(x*257,zavaproj.convertYaxis(QPoint(x,y),z).y()*257),QSize(255,255)));

}

void Export::infoCutting(QList<int> zooms)
{
    countCutting=0;
    foreach (int z, zooms) {
        QPoint NW = zavaproj.pixels2tileFormat(selection->getRectPixels(z).topLeft(),z,ZavaProj::BOTTOM);
        QPoint SE = zavaproj.pixels2tileFormat(selection->getRectPixels(z).bottomRight(),z,ZavaProj::BOTTOM);
        emit messageCutting("In zoom level: "+ QString::number(z)+" will be rendered: "+QString::number((NW.x()-SE.x()) * (SE.y()-NW.y())) + tr(" tiles."));

        for (int x=NW.x(); x<=SE.x(); x++){
            for (int y=SE.y(); y<=NW.y();y++){
                countCutting++;
            }
        }

    }
    emit messageCutting("Totally: "+QString::number(countCutting));
}



bool Export::saveMapTile(QString dirString, int z, int x, int y, QImage tile)
{
    // qDebug()<<"tile"<< z << x << y ;
    QDir dir(dirString);

    if (!dir.exists()) return false;

    dir.setPath(dirString+"\\"+QString::number(z));

    if (!dir.exists()){
        dir.cdUp();
        if (!dir.mkdir(QString::number(z))) return false;
        dir.setPath(dirString+"\\"+QString::number(z));
    }
    dir.setPath(dir.path()+"\\"+QString::number(x));

    if (!dir.exists()){
        dir.cdUp();
        if (!dir.mkdir(QString::number(x))) return false;
        dir.setPath(dir.path()+"\\"+QString::number(x));
    }

    return tile.save(dir.absolutePath()+"\\"+QString::number(y)+".png");
}

void Export::showDialog()
{
    dialogCutting->setModal(true);
    dialogCutting->enableOK(true);
    dialogCutting->exec();
    if (dialogCutting->isRunning){
        dialogCutting->enableOK(false);
        dialogCutting->show();
    }
    //QFuture<void> f = QtConcurrent::run(this,&Export::cutting,dialogCutting->zooms,dialogCutting->fileName);
    this->cutting(dialogCutting->zooms,dialogCutting->fileName);


}




